/*
 *  Copyright (c) 2012 Alaitsev I.K.
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 *  and associated documentation files (the "Software"), to deal in the Software without restriction,
 *  including without limitation the rights to use, copy, modify, merge, publish, distribute,
 *  sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 *  furnished to do so, subject to the following conditions:
 *
 *  The above copyright notice and this permission notice shall be included in all copies or
 *  substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
 *  NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 *  DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 *  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#ifndef CORE_H
#define CORE_H

#include <QObject>
#include <QPointF>
#include <QVector>

class QProcess;

class Core :
    public QObject {
  Q_OBJECT
public:

  explicit Core(QObject *parent = 0);

  typedef QVector <QVector <QPointF> > core_eqp_l_array;

  struct lines_cylinder {
    QVector <double> _xs;
    QVector <double> _ys;
    QVector <double> _fis;
  };

  struct lines_flat {
    QVector <double> _xs;
    QVector <double> _ys;
  };

  struct lines_pack_cylinder {
    QVector <lines_cylinder> _eq_p;
    QVector <lines_cylinder> _l;
    double max_x;
    double max_y;
    double min_x;
    double min_y;
  };

  struct lines_pack_flat {
    lines_flat _eq_p;
    lines_flat _l;
  };

signals:
  void system_changed                           ();
  void system_parameters_changed                ();
  void internal_electrode_radius_valid_no_grade (double out_valid_value);
  void external_electrode_radius_valid_no_grade (double out_valid_value);
  void offset_ie_rel_ee_valid_no_grade          (double out_valid_value);
  void grade_offset_valid                       (double out_valid_value);
  void grade_radius_valid                       (double out_valid_value);
  void potential_difference_valid_no_grade      (double out_valid_value);
  void magnetic_induction_valid_no_grade        (double out_valid_value);
  void grade_potential_difference_valid         (double out_valid_value);
  void grade_magnetic_induction_valid           (double out_valid_value);

public slots:
  /*
   *  Функция обновления системы в случае моделирования движения электронов.
  */
  void update_system ();
  void start_processing ();
  void on_processing_finished ();
  /*
   *  Блок методов для установления и взятия значений параметров системы.
  */
  double internal_electrode_radius_no_grade (double in_new_value);
  double internal_electrode_radius_no_grade () {
    return _internal_electrode_radius_no_grade;
  }

  double external_electrode_radius_no_grade (double in_new_value);
  double external_electrode_radius_no_grade () {
    return _external_electrode_radius_no_grade;
  }

  double offset_ie_rel_ee_no_grade (double in_new_value);
  double offset_ie_rel_ee_no_grade () {
    return _offset_ie_rel_ee_no_grade;
  }

  double grade_radius (double in_new_value);
  double grade_radius () {
    return _grade_radius;
  }

  double grade_offset (double in_new_value);
  double grade_offset () {
    return _grade_offset;
  }

  double potential_difference_no_grade (double in_new_value);
  double potential_difference_no_grade () {
    return _potential_difference_no_grade;
  }

  double magnetic_induction_no_grade (double in_new_value);
  double magnetic_induction_no_grade () {
    return _magnetic_induction_no_grade;
  }

  double grade_potential_difference (double in_new_value);
  double grade_potential_difference () {
    return _grade_potential_difference;
  }

  double grade_magnetic_induction (double in_new_value);
  double grade_magnetic_induction () {
    return _grade_magnetic_induction;
  }
  double initial_electrone_angle (double i_val);
  /*
   *  Возвращает эквипотенциальные линии как массив массивов точек. Наиболее общий метод.
  */
  core_eqp_l_array equipotential_lines (int in_steps_radius,
                                        int in_steps_angle);
  /*
   *  Рассчёт эквинотенциальных линий расличными методами:
   *    cylinder_coordinates - в цилиндрических координатах.
   *    square_coordinates   - в квадратных координатах.
   *    analitic_solution    - приближенное аналитическое решение.
   *    numeric_solution     - точное (?) численное решение.
  */
  lines_pack_cylinder equipotential_lines_cylinder_coordinates_analitic_solution(int in_steps_radius,
                                                                                 int in_steps_angle);
  void equipotential_lines_square_coordinates_analitic_solution   (int in_steps_radius,
                                                                   int in_steps_angle);
  void equipotential_lines_cylinder_coordinates_numeric_solution  (int in_steps_radius,
                                                                   int in_steps_angle);
  void equipotential_lines_square_coordinates_numeric_solution    (int in_steps_radius,
                                                                   int in_steps_angle);

//private:
  public:
  /*
   *  NOTE:
   *    1. Чтобы не возникало путаницы, где анод, а где катод, электроды названы внешним и внутренним.
   *    2. Для удобства(?) все величины представляются в виде
   *          x = xm * 10 ^ g,
   *       Поля с суффиксом no_grade хранят значение xm.
   *       Поля без суффикса хранят значение x.
   *       Поля с перфиксом grade хранят значение gm.
  */
  // Геометрические параметры системы.
  double   _external_electrode_radius_no_grade; // Радиус внешнего электрода.
  double_t _external_electrode_radius;          // Радиус внешнего электрода.
  double   _internal_electrode_radius_no_grade; // Радиус внутреннего электрода.
  double_t _internal_electrode_radius;          // Радиус внутреннего электрода.
  double   _offset_ie_rel_ee_no_grade;          // ie - internal electrode, ee - external electrode, rel - relatively (относительно)
  double_t _offset_ie_rel_ee;                   // ie - internal electrode, ee - external electrode, rel - relatively (относительно)
  double   _grade_radius;                       // Показатель степени 10 для радиусов.
  double   _grade_offset;                       // Показатель степени 10 для отклонения.
  // Электромагнитные переметры системы.
  double   _potential_difference_no_grade;      // Разность потенциалов.
  double_t _potential_difference;               // Разность потенциалов.
  double   _magnetic_induction_no_grade;        // Магнитная индукция.
  double_t _magnetic_induction;                 // Магнитная индукция.
  double   _grade_potential_difference;         // Показатель степени 10 для разности потенциалов.
  double   _grade_magnetic_induction;           // Показатель степени 10 для магнитной индукции.
  // Параметры сеточной модели.
  int      _grid_steps_count_angle;  // Количество шагов изменения угла для узлов сети.
  int      _grid_steps_count_radial; // Количество шагов изменения радиуса для узлов сетки.
  // Начальное положение электрона.
  double _angle;
  // Процесс FEMM
  QProcess * _femm_process;
};

#endif // CORE_H
